﻿#include "ais_point.h"
#include "ais_vector.h"
#include "kernel/transform.h"

CAGD::AIS_Point::AIS_Point(Handle(GeomPoint) point) : AIS_Point(Handle(TopoVertex)(new TopoVertex(point)))
{
}

CAGD::AIS_Point::AIS_Point(Handle(TopoVertex) vertex) : m_vertex(vertex)
{
    // 修改属性
    m_info.psize = 5;
    m_info.size = 1;

    // 构造操作轴并隐藏
    Handle(AIS_Vector) x(new AIS_Vector(Handle(GeomVector)(new GeomVector({1, 0, 0})), vertex->Geom()));
    Handle(AIS_Vector) y(new AIS_Vector(Handle(GeomVector)(new GeomVector({0, 1, 0})), vertex->Geom()));
    Handle(AIS_Vector) z(new AIS_Vector(Handle(GeomVector)(new GeomVector({0, 0, 1})), vertex->Geom()));
    x->GetInfo().status = AIS_Status::HIDDEN;
    y->GetInfo().status = AIS_Status::HIDDEN;
    z->GetInfo().status = AIS_Status::HIDDEN;

    // 推入操作轴作为 AIS_Point 的子节点
    AddChild(x);
    AddChild(y);
    AddChild(z);

    // 将操作轴加入到环境中
    m_context.CreateObject(x);
    m_context.CreateObject(y);
    m_context.CreateObject(z);
}

bool CAGD::AIS_Point::MoveTo(Point pos)
{
    // 隐藏状态不交互，不活跃状态不交互
    if (m_info.status == AIS_Status::HIDDEN || m_info.active == false)
        return false;

    bool hang = false;
    auto tmp = m_info.status;
    m_info.status = AIS_Status::NONE;

    float d;
    auto point = m_vertex->Geom()->Point();

    BPnt2d Q = m_context.GetScreenPoint(Transform::Perform(m_info.modelMat, BPntf(point)), d);
    BPnt2d P = {float(pos.x), float(pos.y)};
    if (d < 2 && (P - Q).Modulus() <= 5)
    {
        SetDepth(d);
        hang = true;
    }

    if (hang)
    {
        if (tmp != AIS_Status::TOUCH)
            m_info.status = AIS_Status::HANG;
        else
            m_info.status = tmp;
    }
    return hang;
}

bool CAGD::AIS_Point::Move(Point pos)
{
    auto &info = m_context.GetInfo();

    // 获得必要点
    float z1 = 0.8;
    BPnt q = Transform::Perform(m_info.modelMat, BPntf(m_vertex->Geom()->Point()));
    BPnt p = m_context.GetSpacePoint(pos);

    // 用鼠标发出的射线作为法向
    auto invertMat = Transform::Inverted(m_info.modelMat);
    BPnt vp = info.viewPos;

    // 计算与平面的交点
    BVec n = (vp - p).Normalized();
    m_vertex->Geom()->SetPoint(Transform::Perform(invertMat, BPntf(p + n * (n * (q - p)))));

    // 刷新着色器
    UpdateArray();

    // 发送移动消息
    PassMessageUp(Message::MOVE_CHILD);

    return true;
}

CAGD::AIS_Type CAGD::AIS_Point::GetType() const
{
    return AIS_Type::POINT;
}

void CAGD::AIS_Point::UpdateInfo()
{
    // 继承模型矩阵
    auto parent = GetParent();
    if (parent != nullptr)
    {
        parent->UpdateInfo();
        m_info.modelMat = parent->GetInfo().modelMat;
    }

    // 根据状态设置颜色
    if (m_info.status == AIS_Status::NONE)
        m_info.color = {1, 1, 1, 1};
    else if (m_info.status == AIS_Status::HANG)
        m_info.color = {0, 0, 1, 1};
    else if (m_info.status == AIS_Status::TOUCH)
        m_info.color = {0, 1, 0, 1};
}

void CAGD::AIS_Point::RecvMessage(Message mess)
{
    // 先调用默认接收函数
    AIS_Base::RecvMessage(mess);

    // none 的目的是让未选中的操作轴都隐藏
    switch (mess)
    {
    case CAGD::Message::NONE: {
        PassMessageDown(Message::HIDE);
        break;
    }
    case CAGD::Message::SELECT: {
        PassMessageDown(Message::SHOW);
        break;
    }
    case CAGD::Message::SHOW_CTRL: {
        m_info.status = AIS_Status::NONE;
        break;
    }
    case CAGD::Message::HIDE_CTRL: {
        // 隐藏时移除所有状态
        m_info.status = AIS_Status::HIDDEN;

        // 隐藏底层操作轴
        PassMessageDown(Message::HIDE);
        break;
    }
    default:
        break;
    }
}

Handle(CAGD::TopoVertex) CAGD::AIS_Point::GetVertex() const
{
    return m_vertex;
}

Handle(CAGD::GeomPoint) CAGD::AIS_Point::GetPoint() const
{
    return m_vertex->Geom();
}